/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package MetricsRetriever.RetrieverComponents;

import JavaMetrics.*;
import DataStructures.Metrics;
import DataStructures.ProjectInformation;
import General.FileManager;
import General.Globals;
import General.RequestMaker;
import gr.spinellis.ckjm.ant.CkjmTask;
import java.io.*;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Manuel
 */

public class JavaManager extends MetricsManager{

    private ProjectInformation projectInfo;
    private ArrayList<String> classFiles;
    private HashMap projectMetrics;
    private FileManager fManager;
    private int[] wmcs;
    private int[] dits;
    private int[] lcoms;
    private int[] nocs;
    private int[] npms;
    private int[] rfcs;
    private int[] cbos;
    private int[] cas;

    public JavaManager(ProjectInformation i,FileManager fm){
        projectMetrics = new HashMap();
        this.projectInfo = i;
        fManager = fm;
    }

    public HashMap getAllCodeMetrics(){
        String file = RequestMaker.storeFile(projectInfo.getArchieveLink().getName(), Globals.DATA_DIRECTORY+"/"+projectInfo.getName());
        classFiles = fManager.process(file);
        if(classFiles.size()<10)
            return null;
        projectMetrics = this.assessMetrics(classFiles);

        //fManager.cleanUp();
        return projectMetrics;
    }

    private HashMap assessMetrics(ArrayList<String> files){
           this.cleanUpList(classFiles);
           HashMap metrics = new HashMap();
           wmcs = new int[files.size()];
           dits = new int[files.size()];
           lcoms = new int[files.size()];
           nocs = new int[files.size()];
           npms = new int[files.size()];
           rfcs = new int[files.size()];
           cbos = new int[files.size()];
           cas = new int[files.size()];
           Metrics m = new Metrics();
           m.setReleaseDate(projectInfo.getArchieveLink().getDate());
           OutputStream outputStream = new ByteArrayOutputStream();
           PrintPlainResults pxml = new PrintPlainResults(new PrintStream(outputStream));
           String[] fileArray = new String[files.size()];
           for(int i = 0;i<files.size();i++)
               fileArray[i] = files.get(i);

           MetricsFilter.runMetrics(fileArray, pxml);
           String metricsString = outputStream.toString();
           String[] metricsArray = metricsString.split("\\r?\\n");
           int index = 0;
           for(int i = 0;i<metricsArray.length;i++){
               String metric = metricsArray[i];
               if(metric != null && !metric.isEmpty() && metric.length()>6){
                   Metrics mc = this.parseMetrics(metric, index);
                   metrics.put(mc.getName(), mc);
                   index++;
               }
           }




           m.setName(".project.");
           m.setDit(this.computeAverage(dits));
           m.setWmc(this.computeAverage(wmcs));
           m.setLcom(this.computeAverage(lcoms));
           m.setNoc(this.computeAverage(nocs));
           m.setRfc(this.computeAverage(rfcs));
           m.setFanin(this.computeAverage(npms));
           m.setCbo(this.computeAverage(cbos));
           m.setNpm(this.computeAverage(npms));

           m.setMaxdit(this.computeMaximum(dits));
           m.setMaxwmc(this.computeMaximum(wmcs));
           m.setMaxlcom(this.computeMaximum(lcoms));
           m.setMaxnoc(this.computeMaximum(nocs));
           m.setMaxrfc(this.computeMaximum(rfcs));
           m.setMaxfanin(this.computeMaximum(npms));
           m.setMaxcbo(this.computeMaximum(cbos));
           m.setMaxnpm(this.computeMaximum(npms));

           m.setMindit(this.computeMinimum(dits));
           m.setMinwmc(this.computeMinimum(wmcs));
           m.setMinlcom(this.computeMinimum(lcoms));
           m.setMinnoc(this.computeMinimum(nocs));
           m.setMinrfc(this.computeMinimum(rfcs));
           m.setMinfanin(this.computeMinimum(npms));
           m.setMincbo(this.computeMinimum(cbos));
           m.setMinnpm(this.computeMinimum(npms));

           System.out.println("average noc: "+m.getNoc());

           metrics.put(m.getName(),m);
           return metrics;

    }

    

    private Metrics parseMetrics(String metrics,int index) {
            String name = metrics.substring(0,metrics.indexOf(" "));
            metrics = metrics.substring(metrics.indexOf(" ")+1);
            String[] sNumbers = metrics.split(" ");
            int[] iNumbers = new int[sNumbers.length];
            for(int i = 0;i<sNumbers.length;i++){
                iNumbers[i] = Integer.parseInt(sNumbers[i]);
            }
            wmcs[index] = iNumbers[0];
            dits[index] = iNumbers[1];
            nocs[index] = iNumbers[2];
            cbos[index] = iNumbers[3];
            rfcs[index] = iNumbers[4];
            lcoms[index] = iNumbers[5];
            cas[index] = iNumbers[6];
            npms[index] = iNumbers[7];

            Metrics currentmetrics = new Metrics();

            currentmetrics.setName(name);
            currentmetrics.setWmc(iNumbers[0]);
            currentmetrics.setDit(iNumbers[1]);
            currentmetrics.setNoc(iNumbers[2]);
            currentmetrics.setCbo(iNumbers[3]);
            currentmetrics.setRfc(iNumbers[4]);
            currentmetrics.setLcom(iNumbers[5]);
            currentmetrics.setNpm(iNumbers[7]);


            return currentmetrics;
    }

    private void cleanUpList(ArrayList<String> files) {
        for (int i = 0;i<files.size();i++){
            if(!files.get(i).endsWith(".class"))
                files.remove(i);
        }
    }

    private double computeAverage(int[] array){
        if(array.length == 0)
            return -1d;
        int sum = 0;
        for(int i = 0;i<array.length;i++){
            sum += array[i];
        }
        DecimalFormat twoDForm = new DecimalFormat("#.####");
        double avg = Double.valueOf(twoDForm.format((double) sum/array.length));
        return avg;
    }

    private double computeMaximum(int[] array){
        if(array.length == 0)
            return -1d;
        int max = -1;
        for(int i = 0;i<array.length;i++){
            if(array[i]>max)
                max = array[i];
        }

        return ((double) max);
    }

    private double computeMinimum(int[] array){
        if(array.length == 0)
            return -1d;
        int min = 100000;
        for(int i = 0;i<array.length;i++){
            if(array[i]<min)
                min = array[i];
        }
        DecimalFormat twoDForm = new DecimalFormat("#.####");

        if(min == 100000)
            return -1d;
        return ((double) min);
    }


}
